﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Kenly.ChineseSegment.Core
{
    /// <summary>
    /// 分词及其出现的次数。
    /// </summary>
    public class SegmentCounter : IComparable<SegmentCounter>
    {
        private string _segment;
        private int _times;
        private decimal _rank;
        private int _defaultIndex;

        /// <summary>
        /// 分词。
        /// </summary>
        public string Segment
        {
            get
            {
                return _segment;
            }
            set
            {
                _segment = value;
            }
        }

        /// <summary>
        /// 出现的次数。
        /// </summary>
        public int Times
        {
            get
            {
                return _times;
            }
            set
            {
                _times = value;
            }
        }

        public decimal Rank
        {
            get
            {
                return _rank;
            }
            set
            {
                _rank = value;
            }
        }

        /// <summary>
        /// 当前对象在链表中的默认位置。
        /// </summary>
        public int DefaultIndex
        {
            get
            {
                return _defaultIndex;
            }
            set
            {
                _defaultIndex = value;
            }
        }

        #region IComparable<SegmentCountPair> 成员

        public int CompareTo(SegmentCounter other)
        {
            if (this.Rank != other.Rank)
            {
                return other.Rank.CompareTo(this.Rank);
            }

            if (this.Times != other.Times)
            {
                return other.Times.CompareTo(this.Times);
            }

            //若次数相同，按默认顺序排序。
            return this.DefaultIndex.CompareTo(other.DefaultIndex);
        }

        #endregion

        /// <summary>
        /// 统计分词出现次数。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static List<SegmentCounter> Count(string text, params string[] separator)
        {
            int baseSegmentCount = 0;
            int facor = 1;
            return Count(text, baseSegmentCount, facor, separator);
        }


        /// <summary>
        /// 统计分词出现次数。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="baseSegmentCount"></param>
        /// <param name="facor"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static List<SegmentCounter> Count(string text, int baseSegmentCount, int facor, params string[] separator)
        {
            if (string.IsNullOrEmpty(text))
            {
                return new List<SegmentCounter>();
            }

            if (separator == null || separator.Length <= 0)
            {
                separator = new string[] { " " };
            }

            if (facor <= 0)
            {
                facor = 1;
            }

            //切分文本
            string[] segments = text.Split(separator, StringSplitOptions.RemoveEmptyEntries);

            //统计分词出现次数
            Dictionary<string, int> countDict = new Dictionary<string, int>();
            AddToDictionary(segments, countDict);

            //统计结果存储于链表
            List<SegmentCounter> counters = AddSegmentCountersToList(countDict);
            CalculateRanks(ref counters, facor, baseSegmentCount);

            return counters;
        }

        private static void AddToDictionary(string[] segments, Dictionary<string, int> countDict)
        {
            foreach (string segment in segments)
            {
                if (segment.Length < 2)
                {
                    continue;
                }

                if (countDict.ContainsKey(segment))
                {
                    countDict[segment] += 1;
                }
                else
                {
                    countDict.Add(segment, 1);
                }
            }
        }

        private static List<SegmentCounter> AddSegmentCountersToList(Dictionary<string, int> countDict)
        {
            List<SegmentCounter> counters = new List<SegmentCounter>();
            foreach (string key in countDict.Keys)
            {
                AddSegmentCounterToList(ref counters, countDict, key);
            }
            return counters;
        }

        private static void AddSegmentCounterToList(ref List<SegmentCounter> counters, Dictionary<string, int> countDict, string key)
        {
            SegmentCounter counter = new SegmentCounter();
            counter.Segment = key;
            counter.Times = countDict[key];

            counters.Add(counter);
            counter.DefaultIndex = counters.IndexOf(counter);
        }

        /// <summary>
        /// 计算每个分词的级别。
        /// </summary>
        /// <param name="counters"></param>
        /// <param name="facor">分词系数</param>
        /// <param name="baseSegmentCount">分词数量。</param>
        private static void CalculateRanks(ref List<SegmentCounter> counters, int facor,int baseSegmentCount)
        {
            int amplify = 100;

            if (baseSegmentCount <= 0)
            {
                baseSegmentCount = counters.Count;
            }

            foreach (SegmentCounter counter in counters)
            {
                counter.Rank = decimal.Divide(counter.Times, baseSegmentCount) * facor;
                counter.Rank += decimal.Divide(counters.Count - counter.DefaultIndex,
                    counters.Count * baseSegmentCount);

                counter.Rank = Math.Round(counter.Rank * amplify, 6);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceCounters"></param>
        /// <param name="newCounters"></param>
        public static void Merge(ref List<SegmentCounter> sourceCounters, List<SegmentCounter> newCounters)
        {
            if (sourceCounters == null)
            {
                return;
            }
            if (newCounters == null || newCounters.Count <= 0)
            {
                return;
            }

            foreach (SegmentCounter newCounter in newCounters)
            {
                Merge(ref sourceCounters, newCounter);
            }
        }

        private static void Merge(ref List<SegmentCounter> sourceCounters, SegmentCounter newCounter)
        {
            if (sourceCounters.Exists(delegate(SegmentCounter sourceCounter)
            {
                return sourceCounter.Segment == newCounter.Segment;
            }))
            {
                SegmentCounter matchCounter = sourceCounters.Find(delegate(SegmentCounter sourceCounter)
                {
                    return sourceCounter.Segment == newCounter.Segment;
                });

                matchCounter.Times += newCounter.Times;
                matchCounter.Rank += newCounter.Rank;
            }
            else
            {
                sourceCounters.Add(newCounter.MemberwiseClone() as SegmentCounter);
            }
        }
    }
}
